home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / StyledEditorKit.java < prev    next >
Text File  |  1998-06-30  |  23KB  |  694 lines

  1. /*
  2.  * @(#)StyledEditorKit.java    1.14 98/04/09
  3.  * 
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  */
  20. package com.sun.java.swing.text;
  21.  
  22. import java.io.*;
  23. import java.awt.*;
  24. import java.awt.event.ActionEvent;
  25. import com.sun.java.swing.event.*;
  26. import com.sun.java.swing.Action;
  27. import com.sun.java.swing.JEditorPane;
  28. import com.sun.java.swing.KeyStroke;
  29.  
  30. /**
  31.  * This is the set of things needed by a text component
  32.  * to be a reasonably functioning editor for some <em>type</em>
  33.  * of text document.  This implementation provides a default
  34.  * implementation which treats text as styled text and 
  35.  * provides a minimal set of actions for editing styled text.
  36.  *
  37.  * @author  Timothy Prinzing
  38.  * @version 1.14 04/09/98
  39.  */
  40. public class StyledEditorKit extends DefaultEditorKit {
  41.  
  42.     /**
  43.      * Gets the input attributes for the pane.  When
  44.      * the caret moves and there is no selection, the
  45.      * input attributes are automatically mutated to 
  46.      * reflect the character attributes of the current
  47.      * caret location.  The styled editing actions 
  48.      * use the input attributes to carry out their 
  49.      * actions.
  50.      *
  51.      * @return the attribute set
  52.      */
  53.     public MutableAttributeSet getInputAttributes() {
  54.     return inputAttributes;
  55.     }
  56.  
  57.     /**
  58.      * Fetches the element representing the current
  59.      * run of character attributes for the caret.
  60.      *
  61.      * @return the element
  62.      */
  63.     public Element getCharacterAttributeRun() {
  64.     return currentRun;
  65.     }
  66.  
  67.     // --- EditorKit methods ---------------------------
  68.  
  69.     /**
  70.      * Create a copy of the editor kit.  This
  71.      * allows an implementation to serve as a prototype
  72.      * for others, so that they can be quickly created.
  73.      *
  74.      * @return the copy
  75.      */
  76.     public Object clone() {
  77.     return new StyledEditorKit();
  78.     }
  79.  
  80.     /**
  81.      * Fetches the command list for the editor.  This is
  82.      * the list of commands supported by the superclass
  83.      * augmented by the collection of commands defined
  84.      * locally for style operations.
  85.      *
  86.      * @return the command list
  87.      */
  88.     public Action[] getActions() {
  89.     return TextAction.augmentList(super.getActions(), this.defaultActions);
  90.     }
  91.    
  92.     /**
  93.      * Creates an uninitialized text storage model
  94.      * that is appropriate for this type of editor.
  95.      *
  96.      * @return the model
  97.      */
  98.     public Document createDefaultDocument() {
  99.     return new DefaultStyledDocument();
  100.     }
  101.  
  102.     /**
  103.      * Called when the kit is being installed into
  104.      * a JEditorPane. 
  105.      *
  106.      * @param c the JEditorPane
  107.      */
  108.     public void install(JEditorPane c) {
  109.     c.addCaretListener(caretHandler);
  110.     }
  111.  
  112.     /**
  113.      * Called when the kit is being removed from the
  114.      * JEditorPane.  This is used to unregister any 
  115.      * listeners that were attached.
  116.      *
  117.      * @param c the JEditorPane
  118.      */
  119.     public void deinstall(JEditorPane c) {
  120.     c.removeCaretListener(caretHandler);
  121.     }
  122.  
  123.    /**
  124.      * Fetches a factory that is suitable for producing 
  125.      * views of any models that are produced by this
  126.      * kit.  This is implemented to return View implementations
  127.      * for the following kinds of elements:
  128.      * <ul>
  129.      * <li>AbstractDocument.ContentElementName
  130.      * <li>AbstractDocument.ParagraphElementName
  131.      * <li>AbstractDocument.SectionElementName
  132.      * <li>StyleConstants.ComponentElementName
  133.      * <li>StyleConstants.IconElementName
  134.      * </ul>
  135.      *
  136.      * @return the factory
  137.      */
  138.     public ViewFactory getViewFactory() {
  139.     return defaultFactory;
  140.     }
  141.  
  142.     private static final ViewFactory defaultFactory = new StyledViewFactory();
  143.  
  144.     Element currentRun;
  145.     Element currentParagraph;
  146.     MutableAttributeSet inputAttributes = new SimpleAttributeSet() {
  147.         public AttributeSet getResolveParent() {
  148.         return (currentParagraph != null) ? currentParagraph.getAttributes() : null;
  149.     }
  150.     };
  151.     
  152.     private AttributeTracker caretHandler = new AttributeTracker();
  153.  
  154.     /**
  155.      * Tracks caret movement and keeps the input attributes set 
  156.      * to reflect the current set of attribute definitions at the 
  157.      * caret position. 
  158.      */
  159.     class AttributeTracker implements CaretListener, Serializable {
  160.  
  161.     public void caretUpdate(CaretEvent e) {
  162.         int dot = e.getDot();
  163.         int mark = e.getMark();
  164.         if (dot == mark) {
  165.         // record current character attributes.
  166.         JTextComponent c = (JTextComponent) e.getSource();
  167.         StyledDocument doc = (StyledDocument) c.getDocument();
  168.         Element run = doc.getCharacterElement(Math.max(dot-1, 0));
  169.         currentParagraph = doc.getParagraphElement(dot);
  170.         if (run != currentRun) {
  171.             /*
  172.              * PENDING(prinz) All attributes that represent a single
  173.              * glyph position and can't be inserted into should be 
  174.              * removed from the input attributes... this requires 
  175.              * mixing in an interface to indicate that condition.  
  176.              * When we can add things again this logic needs to be
  177.              * improved!!
  178.              */ 
  179.             currentRun = run;
  180.             inputAttributes.removeAttributes(inputAttributes);
  181.             inputAttributes.addAttributes(currentRun.getAttributes());
  182.             inputAttributes.removeAttribute(StyleConstants.ComponentAttribute);
  183.             inputAttributes.removeAttribute(StyleConstants.IconAttribute);
  184.             inputAttributes.removeAttribute(AbstractDocument.ElementNameAttribute);
  185.         }
  186.         }
  187.     }
  188.     }
  189.  
  190.     // ---- default ViewFactory implementation ---------------------
  191.  
  192.     static class StyledViewFactory implements ViewFactory {
  193.  
  194.         public View create(Element elem) {
  195.         String kind = elem.getName();
  196.         if (kind != null) {
  197.         if (kind.equals(AbstractDocument.ContentElementName)) {
  198.             return new LabelView(elem);
  199.         } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
  200.             return new ParagraphView(elem);
  201.         } else if (kind.equals(AbstractDocument.SectionElementName)) {
  202.             return new BoxView(elem, View.Y_AXIS);
  203.         } else if (kind.equals(StyleConstants.ComponentElementName)) {
  204.             return new ComponentView(elem);
  205.         } else if (kind.equals(StyleConstants.IconElementName)) {
  206.             return new IconView(elem);
  207.         }
  208.         }
  209.     
  210.         // default to text display
  211.         return new LabelView(elem);
  212.     }
  213.  
  214.     }
  215.  
  216.     // --- Action implementations ---------------------------------
  217.  
  218.     private static final Action[] defaultActions = {
  219.     new FontFamilyAction("font-family-SansSerif", "SansSerif"),
  220.     new FontFamilyAction("font-family-Monospaced", "Monospaced"),
  221.     new FontFamilyAction("font-family-Serif", "Serif"),
  222.     new FontSizeAction("font-size-8", 8),
  223.     new FontSizeAction("font-size-10", 10),
  224.     new FontSizeAction("font-size-12", 12),
  225.     new FontSizeAction("font-size-14", 14),
  226.     new FontSizeAction("font-size-16", 16),
  227.     new FontSizeAction("font-size-18", 18),
  228.     new FontSizeAction("font-size-24", 24),
  229.     new FontSizeAction("font-size-36", 36),
  230.     new FontSizeAction("font-size-48", 48),
  231.     new AlignmentAction("left-justify", StyleConstants.ALIGN_LEFT),
  232.     new AlignmentAction("center-justify", StyleConstants.ALIGN_CENTER),
  233.     new AlignmentAction("right-justify", StyleConstants.ALIGN_RIGHT),
  234.     new BoldAction(),
  235.     new ItalicAction(),
  236.     new UnderlineAction()
  237.     };
  238.  
  239.     /**
  240.      * An action that assumes it's being fired on a JEditorPane
  241.      * with a StyledEditorKit (or subclass) installed.  This has
  242.      * some convenience methods for causing character or paragraph
  243.      * level attribute changes.  The convenience methods will 
  244.      * throw an IllegalArgumentException if the assumption of
  245.      * a StyledDocument, a JEditorPane, or a StyledEditorKit
  246.      * fail to be true.
  247.      * <p>
  248.      * The component that gets acted upon by the action 
  249.      * will be the source of the ActionEvent if the source
  250.      * can be narrowed to a JEditorPane type.  If the source
  251.      * can't be narrowed, the most recently focused text 
  252.      * component is changed.  If neither of these are the
  253.      * case, the action cannot be performed.
  254.      * <p>
  255.      * Warning: serialized objects of this class will not be compatible with
  256.      * future swing releases.  The current serialization support is appropriate
  257.      * for short term storage or RMI between Swing1.0 applications.  It will
  258.      * not be possible to load serialized Swing1.0 objects with future releases
  259.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  260.      * baseline for the serialized form of Swing objects.
  261.      */
  262.     public abstract static class StyledTextAction extends TextAction {
  263.  
  264.         /**
  265.          * Creates a new StyledTextAction from a string action name.
  266.          *
  267.          * @param nm the name of the action
  268.          */
  269.         public StyledTextAction(String nm) {
  270.         super(nm);
  271.     }
  272.  
  273.         /**
  274.          * Gets the target editor for an action.
  275.          *
  276.          * @param e the action event
  277.          * @return the editor
  278.          * @exception IllegalArgumentException for an invalid target
  279.          */
  280.         protected final JEditorPane getEditor(ActionEvent e) {
  281.         if (e != null) {
  282.         Object o = e.getSource();
  283.         if (o instanceof JEditorPane) {
  284.             return (JEditorPane) o;
  285.         }
  286.         JTextComponent c = getFocusedComponent();
  287.         if (c instanceof JEditorPane) {
  288.             return (JEditorPane) c;
  289.         }
  290.         }
  291.         throw new IllegalArgumentException("target must be JEditorPane");
  292.     }
  293.  
  294.         /**
  295.          * Gets the document associated with an editor pane.
  296.          *
  297.          * @param e the editor
  298.          * @return the document
  299.          * @exception IllegalArgumentException for the wrong document type
  300.          */
  301.         protected final StyledDocument getStyledDocument(JEditorPane e) {
  302.         Document d = e.getDocument();
  303.         if (d instanceof StyledDocument) {
  304.         return (StyledDocument) d;
  305.         }
  306.         throw new IllegalArgumentException("document must be StyledDocument");
  307.     }
  308.  
  309.         /**
  310.          * Gets the editor kit associated with an editor pane.
  311.          *
  312.          * @param e the editor pane
  313.          * @return the kit
  314.          * @exception IllegalArgumentException for the wrong document type
  315.          */
  316.         protected final StyledEditorKit getStyledEditorKit(JEditorPane e) {
  317.         EditorKit k = e.getEditorKit();
  318.         if (k instanceof StyledEditorKit) {
  319.         return (StyledEditorKit) k;
  320.         }
  321.         throw new IllegalArgumentException("EditorKit must be StyledEditorKit");
  322.     }
  323.  
  324.     /**
  325.      * Applies the given attributes to character 
  326.      * content.  If there is a selection, the attributes
  327.      * are applied to the selection range.  If there
  328.      * is no selection, the attributes are applied to
  329.      * the input attribute set which defines the attributes
  330.      * for any new text that gets inserted.
  331.      *
  332.          * @param editor the editor
  333.      * @param attr the attributes
  334.      * @param replace   if true, then replace the existing attributes first
  335.      */
  336.         protected final void setCharacterAttributes(JEditorPane editor, 
  337.                           AttributeSet attr, boolean replace) {
  338.         int p0 = editor.getSelectionStart();
  339.         int p1 = editor.getSelectionEnd();
  340.         if (p0 != p1) {
  341.         StyledDocument doc = getStyledDocument(editor);
  342.         doc.setCharacterAttributes(p0, p1 - p0, attr, replace);
  343.         } else {
  344.         StyledEditorKit k = getStyledEditorKit(editor);
  345.         MutableAttributeSet inputAttributes = k.getInputAttributes();
  346.         if (replace) {
  347.             inputAttributes.removeAttributes(inputAttributes);
  348.         }
  349.         inputAttributes.addAttributes(attr);
  350.         }
  351.     }
  352.  
  353.     /**
  354.      * Applies the given attributes to paragraphs.  If
  355.      * there is a selection, the attributes are applied
  356.      * to the paragraphs that intersect the selection.
  357.      * if there is no selection, the attributes are applied
  358.      * to the paragraph at the current caret position.
  359.      *
  360.          * @param editor the editor
  361.      * @param attr the attributes
  362.      * @param replace   if true, replace the existing attributes first
  363.      */
  364.         protected final void setParagraphAttributes(JEditorPane editor, 
  365.                        AttributeSet attr, boolean replace) {
  366.         int p0 = editor.getSelectionStart();
  367.         int p1 = editor.getSelectionEnd();
  368.         StyledDocument doc = getStyledDocument(editor);
  369.         doc.setParagraphAttributes(p0, p1 - p0, attr, replace);
  370.     }
  371.  
  372.     }
  373.  
  374.     /**
  375.      * An action to set the font family in the associated
  376.      * JEditorPane.  This will use the family specified as
  377.      * the command string on the ActionEvent if there is one,
  378.      * otherwise the family that was initialized with will be used.
  379.      * <p>
  380.      * Warning: serialized objects of this class will not be compatible with
  381.      * future swing releases.  The current serialization support is appropriate
  382.      * for short term storage or RMI between Swing1.0 applications.  It will
  383.      * not be possible to load serialized Swing1.0 objects with future releases
  384.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  385.      * baseline for the serialized form of Swing objects.
  386.      */
  387.     public static class FontFamilyAction extends StyledTextAction {
  388.  
  389.         /**
  390.          * Creates a new FontFamilyAction.
  391.          *
  392.          * @param nm the action name
  393.          * @param family the font family
  394.          */
  395.     public FontFamilyAction(String nm, String family) {
  396.         super(nm);
  397.         this.family = family;
  398.     }
  399.  
  400.         /**
  401.          * Sets the font family.
  402.          *
  403.          * @param e the event
  404.          */
  405.         public void actionPerformed(ActionEvent e) {
  406.         JEditorPane editor = getEditor(e);
  407.         if (editor != null) {
  408.         String family = this.family;
  409.         if ((e != null) && (e.getSource() == editor)) {
  410.             String s = e.getActionCommand();
  411.             if (s != null) {
  412.             family = s;
  413.             System.out.println("s: " + s);
  414.             }
  415.         }
  416.         if (family != null) {
  417.             MutableAttributeSet attr = new SimpleAttributeSet();
  418.             StyleConstants.setFontFamily(attr, family);
  419.             setCharacterAttributes(editor, attr, false);
  420.         } else {
  421.             Toolkit.getDefaultToolkit().beep();
  422.         }
  423.         }
  424.     }
  425.  
  426.     private String family;
  427.     }
  428.  
  429.     /**
  430.      * An action to set the font size in the associated
  431.      * JEditorPane.  This will use the size specified as
  432.      * the command string on the ActionEvent if there is one,
  433.      * otherwise the size that was initialized with will be used.
  434.      * <p>
  435.      * Warning: serialized objects of this class will not be compatible with
  436.      * future swing releases.  The current serialization support is appropriate
  437.      * for short term storage or RMI between Swing1.0 applications.  It will
  438.      * not be possible to load serialized Swing1.0 objects with future releases
  439.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  440.      * baseline for the serialized form of Swing objects.
  441.      */
  442.     public static class FontSizeAction extends StyledTextAction {
  443.  
  444.         /**
  445.          * Creates a new FontSizeAction.
  446.          *
  447.          * @param nm the action name
  448.          * @param size the font size
  449.          */
  450.     public FontSizeAction(String nm, int size) {
  451.         super(nm);
  452.         this.size = size;
  453.     }
  454.  
  455.         /**
  456.          * Sets the font size.
  457.          *
  458.          * @param e the action event
  459.          */
  460.         public void actionPerformed(ActionEvent e) {
  461.         JEditorPane editor = getEditor(e);
  462.         if (editor != null) {
  463.         int size = this.size;
  464.         if ((e != null) && (e.getSource() == editor)) {
  465.             String s = e.getActionCommand();
  466.             try {
  467.             size = Integer.parseInt(s, 10);
  468.             } catch (NumberFormatException nfe) {
  469.             }
  470.         }
  471.         if (size != 0) {
  472.             MutableAttributeSet attr = new SimpleAttributeSet();
  473.             StyleConstants.setFontSize(attr, size);
  474.             setCharacterAttributes(editor, attr, false);
  475.         } else {
  476.             Toolkit.getDefaultToolkit().beep();
  477.         }
  478.         }
  479.     }
  480.  
  481.     private int size;
  482.     }
  483.  
  484.     /**
  485.      * An action to set the foreground color in the focused 
  486.      * JEditorPane by calling its setForeground method.
  487.      * <p>
  488.      * Warning: serialized objects of this class will not be compatible with
  489.      * future swing releases.  The current serialization support is appropriate
  490.      * for short term storage or RMI between Swing1.0 applications.  It will
  491.      * not be possible to load serialized Swing1.0 objects with future releases
  492.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  493.      * baseline for the serialized form of Swing objects.
  494.      */
  495.     public static class ForegroundAction extends StyledTextAction {
  496.  
  497.         /**
  498.          * Creates a new ForegroundAction.
  499.          *
  500.          * @param nm the action name
  501.          * @param fg the foreground color
  502.          */
  503.     public ForegroundAction(String nm, Color fg) {
  504.         super(nm);
  505.         this.fg = fg;
  506.     }
  507.  
  508.         /**
  509.          * Sets the foreground color.
  510.          *
  511.          * @param e the action event
  512.          */
  513.         public void actionPerformed(ActionEvent e) {
  514.         JEditorPane editor = getEditor(e);
  515.         if (editor != null) {
  516.         Color fg = this.fg;
  517.         if ((e != null) && (e.getSource() == editor)) {
  518.             String s = e.getActionCommand();
  519.             try {
  520.             fg = Color.decode(s);
  521.             } catch (NumberFormatException nfe) {
  522.             }
  523.         }
  524.         if (fg != null) {
  525.             MutableAttributeSet attr = new SimpleAttributeSet();
  526.             StyleConstants.setForeground(attr, fg);
  527.             setCharacterAttributes(editor, attr, false);
  528.         } else {
  529.             Toolkit.getDefaultToolkit().beep();
  530.         }
  531.         }
  532.     }
  533.  
  534.     private Color fg;
  535.     }
  536.  
  537.     /**
  538.      * An action to set paragraph alignment.
  539.      * <p>
  540.      * Warning: serialized objects of this class will not be compatible with
  541.      * future swing releases.  The current serialization support is appropriate
  542.      * for short term storage or RMI between Swing1.0 applications.  It will
  543.      * not be possible to load serialized Swing1.0 objects with future releases
  544.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  545.      * baseline for the serialized form of Swing objects.
  546.      */
  547.     public static class AlignmentAction extends StyledTextAction {
  548.  
  549.         /**
  550.          * Creates a new AlignmentAction.
  551.          *
  552.          * @param nm the action name
  553.          * @param a the alignment >= 0
  554.          */
  555.     public AlignmentAction(String nm, int a) {
  556.         super(nm);
  557.         this.a = a;
  558.     }
  559.  
  560.         /**
  561.          * Sets the alignment.
  562.          *
  563.          * @param e the action event
  564.          */
  565.         public void actionPerformed(ActionEvent e) {
  566.         JEditorPane editor = getEditor(e);
  567.         if (editor != null) {
  568.         int a = this.a;
  569.         if ((e != null) && (e.getSource() == editor)) {
  570.             String s = e.getActionCommand();
  571.             try {
  572.             a = Integer.parseInt(s, 10);
  573.             } catch (NumberFormatException nfe) {
  574.             }
  575.         }
  576.         MutableAttributeSet attr = new SimpleAttributeSet();
  577.         StyleConstants.setAlignment(attr, a);
  578.         setParagraphAttributes(editor, attr, false);
  579.         }
  580.     }
  581.  
  582.     private int a;
  583.     }
  584.  
  585.     /**
  586.      * An action to toggle the bold attribute.
  587.      * <p>
  588.      * Warning: serialized objects of this class will not be compatible with
  589.      * future swing releases.  The current serialization support is appropriate
  590.      * for short term storage or RMI between Swing1.0 applications.  It will
  591.      * not be possible to load serialized Swing1.0 objects with future releases
  592.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  593.      * baseline for the serialized form of Swing objects.
  594.      */
  595.     public static class BoldAction extends StyledTextAction {
  596.  
  597.         /**
  598.          * Constructs a new BoldAction.
  599.          */
  600.     public BoldAction() {
  601.         super("font-bold");
  602.     }
  603.  
  604.         /**
  605.          * Toggles the bold attribute.
  606.          *
  607.          * @param e the action event
  608.          */
  609.         public void actionPerformed(ActionEvent e) {
  610.         JEditorPane editor = getEditor(e);
  611.         if (editor != null) {
  612.         StyledEditorKit kit = getStyledEditorKit(editor);
  613.         MutableAttributeSet attr = kit.getInputAttributes();
  614.         boolean bold = (StyleConstants.isBold(attr)) ? false : true;
  615.         StyleConstants.setBold(attr, bold);
  616.         setCharacterAttributes(editor, attr, false);
  617.         }
  618.     }
  619.     }
  620.  
  621.     /**
  622.      * An action to toggle the italic attribute.
  623.      * <p>
  624.      * Warning: serialized objects of this class will not be compatible with
  625.      * future swing releases.  The current serialization support is appropriate
  626.      * for short term storage or RMI between Swing1.0 applications.  It will
  627.      * not be possible to load serialized Swing1.0 objects with future releases
  628.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  629.      * baseline for the serialized form of Swing objects.
  630.      */
  631.     public static class ItalicAction extends StyledTextAction {
  632.  
  633.         /**
  634.          * Constructs a new ItalicAction.
  635.          */
  636.     public ItalicAction() {
  637.         super("font-italic");
  638.     }
  639.  
  640.         /**
  641.          * Toggles the italic attribute.
  642.          *
  643.          * @param e the action event
  644.          */
  645.         public void actionPerformed(ActionEvent e) {
  646.         JEditorPane editor = getEditor(e);
  647.         if (editor != null) {
  648.         StyledEditorKit kit = getStyledEditorKit(editor);
  649.         MutableAttributeSet attr = kit.getInputAttributes();
  650.         boolean italic = (StyleConstants.isItalic(attr)) ? false : true;
  651.         StyleConstants.setItalic(attr, italic);
  652.         setCharacterAttributes(editor, attr, false);
  653.         }
  654.     }
  655.     }
  656.  
  657.     /**
  658.      * An action to toggle the underline attribute.
  659.      * <p>
  660.      * Warning: serialized objects of this class will not be compatible with
  661.      * future swing releases.  The current serialization support is appropriate
  662.      * for short term storage or RMI between Swing1.0 applications.  It will
  663.      * not be possible to load serialized Swing1.0 objects with future releases
  664.      * of Swing.  The JDK1.2 release of Swing will be the compatibility
  665.      * baseline for the serialized form of Swing objects.
  666.      */
  667.     public static class UnderlineAction extends StyledTextAction {
  668.  
  669.         /**
  670.          * Constructs a new UnderlineAction.
  671.          */
  672.     public UnderlineAction() {
  673.         super("font-underline");
  674.     }
  675.  
  676.         /**
  677.          * Toggles the Underline attribute.
  678.          *
  679.          * @param e the action event
  680.          */
  681.         public void actionPerformed(ActionEvent e) {
  682.         JEditorPane editor = getEditor(e);
  683.         if (editor != null) {
  684.         StyledEditorKit kit = getStyledEditorKit(editor);
  685.         MutableAttributeSet attr = kit.getInputAttributes();
  686.         boolean underline = (StyleConstants.isUnderline(attr)) ? false : true;
  687.         StyleConstants.setUnderline(attr, underline);
  688.         setCharacterAttributes(editor, attr, false);
  689.         }
  690.     }
  691.     }
  692.  
  693. }
  694.